#include "VSController.h"
#include "VSMath.h"
#include "VSStream.h"
#include "VSGraphicInclude.h"
using namespace VSEngine2;
IMPLEMENT_RTTI_NoCreateFun(VSController,VSObject)
VSController::VSController()
{
	m_uiRepeatType = RT_NONE;
	m_dMinTime = 0.0;
	m_dMaxTime = 0.0;
	m_dPhase = 0.0;
	m_dFrequency = 1.0;
	m_pObject = NULL;
	m_dLastAppTime = 0;
	m_dIntervalTime = 0.0;
	m_bStart = 0;
	m_dStartSystemTime = 0;
	m_dNowAppTime = 0.0;
	m_bEnable = true;
	//m_uiUpdateType = UT_FORWARD;
}
VSController::~VSController()
{
	m_pObject = NULL;
}
bool VSController::UpdateEx(double aAppTime)
{
	return 1;
}
bool VSController::Update(double dAppTime)
{
	if(!m_bEnable)
	{
		m_bStart = 0;
		return 0;
	}
	
	if(!m_bStart)
	{
		m_dStartSystemTime = dAppTime;
		m_bStart = 1;
		m_dLastAppTime = 0;
		m_dTimeSum = 0;
	}

	dAppTime = dAppTime - m_dStartSystemTime;

	dAppTime = GetControlTime(dAppTime);

	m_dNowAppTime =dAppTime;
	m_dIntervalTime = abs(dAppTime - m_dLastAppTime);
	m_dTimeSum += m_dIntervalTime;

	UpdateEx(dAppTime);

	m_dLastAppTime = dAppTime;
	return 1;
}
double VSController::GetControlTime(double dAppTime)
{
	double dCtrlTime = m_dFrequency * dAppTime + m_dPhase;
	if(m_uiRepeatType == RT_NONE)
	{
		return dCtrlTime;
	}
	if (m_uiRepeatType == RT_CLAMP)
	{
		if (dCtrlTime < m_dMinTime)
		{
			return m_dMinTime;
		}
		if (dCtrlTime > m_dMaxTime)
		{
			return m_dMaxTime;
		}
		return dCtrlTime;
	}

	double dRange = m_dMaxTime - m_dMinTime;
	if (dRange > 0.0)
	{
		double dMultiples = (dCtrlTime - m_dMinTime) / dRange;
		double dIntTime = floor(dMultiples);
		double dFrcTime = dMultiples - dIntTime;
		if (m_uiRepeatType == RT_WRAP)
		{
			return m_dMinTime + dFrcTime * dRange;
		}
		if(m_uiRepeatType == RT_CYCLE)
		{
			if (int(dIntTime) & 1)
			{
				// backward time
				return m_dMaxTime - dFrcTime * dRange;

			}
			else
			{
				// forward time
				return m_dMinTime + dFrcTime*  dRange;
				
			}
		}
		
		return m_dMinTime;
	}
	else
	{
		return m_dMinTime;
	}

}
unsigned int VSController::DiskUse()const
{
	unsigned int Use = VSObject::DiskUse();
	Use += sizeof(unsigned int);
	Use += sizeof(double) * 4;
	Use += sizeof(VSObject *);
	Use += sizeof(bool);
	return Use;
}
bool VSController::Save(VSStream & rStream,unsigned int &iSaveUse)const
{
	if(!VSObject::Save(rStream,iSaveUse))
		return 0;

	if(!rStream.Write(&m_bEnable,sizeof(bool)))
		return 0;
	iSaveUse += sizeof(bool);
	if(!rStream.Write(&m_uiRepeatType,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	if(!rStream.Write(&m_dMinTime,sizeof(double)))
		return 0;
	iSaveUse += sizeof(double);

	if(!rStream.Write(&m_dMaxTime,sizeof(double)))
		return 0;
	iSaveUse += sizeof(double);

	if(!rStream.Write(&m_dPhase,sizeof(double)))
		return 0;
	iSaveUse += sizeof(double);

	if(!rStream.Write(&m_dFrequency,sizeof(double)))
		return 0;
	iSaveUse += sizeof(double);


	
	if(!m_pObject)
		return 0;
// 	VSObject * pObject = m_pObject;
// 	if(!rStream.Write(&pObject,sizeof(VSObject *)))
// 		return 0;

	if(!rStream.WriteObjectPtr(m_pObject))
		return 0;
	iSaveUse += sizeof(VSObject *);



	return 1;
}
bool VSController::Load(VSStream & rStream,unsigned int &iSaveUse)
{
	if(!VSObject::Load(rStream,iSaveUse))
		return 0;

	if(!rStream.Read(&m_bEnable,sizeof(bool)))
		return 0;
	iSaveUse += sizeof(bool);
	if(!rStream.Read(&m_uiRepeatType,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	if(!rStream.Read(&m_dMinTime,sizeof(double)))
		return 0;
	iSaveUse += sizeof(double);

	if(!rStream.Read(&m_dMaxTime,sizeof(double)))
		return 0;
	iSaveUse += sizeof(double);

	if(!rStream.Read(&m_dPhase,sizeof(double)))
		return 0;
	iSaveUse += sizeof(double);

	if(!rStream.Read(&m_dFrequency,sizeof(double)))
		return 0;
	iSaveUse += sizeof(double);


// 	VSObject * pObject = NULL;
// 	if(!rStream.Read(&pObject,sizeof(VSObject *)))
// 		return 0;
// 	AddLink(pObject);

	if(!rStream.ReadObjectPtr(m_pObject))
		return 0;
	iSaveUse += sizeof(VSObject *);

	return 1;
}
bool VSController::Clone(const VSObject *pObject,unsigned int uiType)
{
	const VSController* Temp = DynamicCast<VSController>(pObject); 
	if(!Temp)
		return 0;
	if(VSObject::Clone(pObject,uiType))
	{
		
		m_uiRepeatType = Temp->m_uiRepeatType;
		m_dMinTime = Temp->m_dMinTime;
		m_dMaxTime = Temp->m_dMaxTime;
		m_dPhase = Temp->m_dPhase;
		m_dFrequency = Temp->m_dFrequency;
		m_bEnable = Temp->m_bEnable;
		//m_pObject = Temp->m_pObject;
		return 1;
	}
	else
	{
		return 0;

	}

}
bool VSController::Link(VSStream & rStream)
{
	if(!VSObject::Link(rStream))
		return 0;

	//m_pObject = (VSObject *)rStream.GetMapValue(GetNextLink());

	rStream.LinkObjectPtr(m_pObject);
	return 1;
}
bool VSController::Register(VSStream & rStream)const
{
	if (rStream.IsObjectRegister(this))
	{
		return 1;
	}
	if(!VSObject::Register(rStream))
		return 0;
	if(m_pObject)
	{
		if(!m_pObject->Register(rStream))
			return 0;
	}
	return 1;
}
bool VSController::SetObject(VSObject * pObject)
{
	if(!pObject)
		return 0;
	m_pObject = pObject;
	return 1;
}
double VSController::GetTime(double fTime, double fMin,double fMax,unsigned int uiRepeatType)
{
	if(uiRepeatType == RT_NONE || uiRepeatType >= RT_MAX)
	{
		return fTime;
	}
	if (uiRepeatType == RT_CLAMP)
	{
		if (fTime < fMin)
		{
			return fMin;
		}
		if (fTime > fMax)
		{
			return fMax;
		}
		return fTime;
	}

	double dRange = fMax - fMin;
	if (dRange > 0.0)
	{
		double dMultiples = (fTime - fMin) / dRange;
		double dIntTime = floor(dMultiples);
		double dFrcTime = dMultiples - dIntTime;
		if (uiRepeatType == RT_WRAP)
		{
			return fMin + dFrcTime * dRange;
		}
		if(uiRepeatType == RT_CYCLE)
		{
			if (int(dIntTime) & 1)
			{
				// backward time
				return fMax - dFrcTime * dRange;

			}
			else
			{
				// forward time
				return fMin + dFrcTime*  dRange;

			}
		}

		return fMin;
	}
	else
	{
		return fMin;
	}
}